/**
 * Definition of DList.hpp.
 *
 * Note: You can check out all sources as eclipse cpp project
 *       over http://stuff-from-hell.googlecode.com/svn/trunk/cpp_ex
 *
 * @author  Benjamin Friedrich (3453464)
 * 			benjamin_friedrich@gmx.de
 * @version 1.0  17.01.2009
 */
#include "DList.hpp"
#include <cstring>

const char *               DList::TO_STRING_SEPARATOR = " -- ";
const DListElement         DList::DListIterator::THE_END = {"THE_END", 0, 0};
const DList::DListIterator DList::DListIterator::PSEUDO_LAST(
								const_cast<DListElement*>(&DList::DListIterator::THE_END)
															);


DList::DList(const char **charStrings, const int &numberOfStrings)
{
	this->init();

	for(int i = 0; i < numberOfStrings; i++)
	{
		this->pushBack(charStrings[i]);
	}
}


DList::DList(const DList &list)
{
	this->init();
	this->importList(list);
}


void DList::init()
{
	this->numberOfElements = NULL;
	this->first            = NULL;
	this->last             = NULL;
}


void DList::importList(const DList &list)
{
	DListElement *tmpElement = list.first;

	while(tmpElement != NULL)
	{
	    pushBack(tmpElement->charString);
		tmpElement = tmpElement->next;
	}
}


void DList::clear()
{
	while(this->numberOfElements != 0)
	{
		this->remove(0);
	}
}


bool DList::insert(const unsigned int &position, const char *charString)
{
	if(position > this->numberOfElements)
	{
		return false;
	}

	DListElement *newElement = new DListElement;
	newElement->next         = 0;
	newElement->previous     = 0;
	newElement->charString   = charString;

	if(this->numberOfElements == 0)
	{
  	   this->first = newElement;
	   this->last  = newElement;
	}
	else if(position == this->numberOfElements)
	{
		newElement->previous = this->last;
		this->last->next     = newElement;
		this->last           = newElement;
	}
	else
	{
		DListElement *tmp = this->first;

		for(unsigned int i = 0; i != position; i++)
		{
			tmp = tmp->next;
		}

		newElement->next     = tmp;
		newElement->previous = tmp->previous;
		tmp       ->previous = newElement;

		if(newElement->previous != NULL)
		   newElement->previous->next = newElement;

		if(position == 0)
		{
			this->first = newElement;
		}
	}

	this->numberOfElements++;

	return true;
}


const char* DList::remove(const unsigned int &position)
{
	if(this->numberOfElements <= 0)
	{
		return NULL;
	}

	if(position < 0)
	{
		return NULL;
	}

	if(position >= this->numberOfElements)
	{
		return NULL;
	}

	DListElement *tmp = this->first;

	for(unsigned int i = 0; i != position; i++)
	{
		tmp = tmp->next;
	}

	if(tmp->previous != NULL)
	{
	   tmp->previous->next = tmp->next;
	}

	if(tmp->next != NULL)
	{
	   tmp->next->previous = tmp->previous;
	}

	if(tmp == this->first)
	{
		this->first = tmp->next;
	}

	if(tmp == this->last)
	{
		this->last = tmp->previous;
	}

	const char *charString = tmp->charString;

	delete tmp;

	this->numberOfElements--;

	return charString;
}


DList& DList::operator=(const DList &list)
{
	this->clear();
	this->importList(list);

	return *this;
}


DList& DList::operator+=(const DList &list)
{
	*this = *this + list;
	return  *this;
}


bool  operator==(const DList &list1, const DList &list2)
{
	using namespace std;

	if(&list1 == &list2)
	{
		return true;
	}

	if(list1.numberOfElements != list2.numberOfElements)
	{
		return false;
	}


	DListElement *elementList1 = list1.first;
	DListElement *elementList2 = list2.first;

	while(elementList1 != NULL && elementList2 != NULL)
	{

		if(strcmp(elementList1->charString, elementList2->charString))
		{
			return false;
		}

		elementList1  = elementList1 ->next;
		elementList2  = elementList2 ->next;
	}

	return true;
}


DList operator+ (const DList &listHead, const DList &listTail)
{
	DList newList(listHead);

	DListElement *tmpElement = listTail.first;

	while(tmpElement != NULL)
	{
		newList.pushBack(tmpElement->charString);
		tmpElement = tmpElement->next;
	}

	return newList;
}


const char *DList::operator[](const unsigned int &index) const
{
	if(index >= this->numberOfElements)
	{
		return NULL;
	}


	if(index == this->numberOfElements -1)
	{
		return this->last->charString;
	}
	else
	{
		DListElement *tmpElement = this->first;

		for(unsigned int i = 0; i != index; i++)
		{
			tmpElement = tmpElement->next;
		}

		return tmpElement->charString;
	}
}


const std::string DList::toString() const
{
	std::string  tmpString   = "";
	DListElement *tmpElement = this->first;

	while(tmpElement != NULL)
	{
		tmpString  += tmpElement->charString;

		if(tmpElement->next != NULL)
		{
			tmpString += DList::TO_STRING_SEPARATOR ;
		}

		tmpElement = tmpElement->next;
	}

	return tmpString;
}


DList::DListIterator DList::DListIterator::operator++(int)
{
	if(this->current->next)
	{
		DList::DListIterator iterator(this->current);
		this->current = this->current->next;

		return iterator;
	}
	else
	{
		*this = DList::DListIterator::PSEUDO_LAST;
		return *this;
	}
}


bool operator==(const DList::DListIterator &iterator1,const DList::DListIterator &iterator2)
{
	using namespace std;

	//-- are iterator1 and iterator2 the same object?
	if(&iterator1 == &iterator2 )
	{
		return true;
	}

	//-- is one of both equal NULL and one not?
	if( (iterator1.current == NULL) ^ (iterator2.current == NULL))
	{
		return false;
	}

	//-- if iterator1.current and iterator2.current are not equal NULL,
	//-- operator==() must compare the previous and the next element of
	//-- the current element.
	if(iterator1.current && iterator2.current)
	{
		//-- is one of both equal NULL and one not?
		if( (iterator1.current->next == NULL) ^ (iterator2.current->next == NULL))
		{
			return false;
		}

		//-- is one of both equal NULL and one not?
		if( (iterator1.current->previous == NULL) ^ (iterator2.current->previous == NULL) )
		{
			return false;
		}

		//-- checks the equality of the character strings of the current elements
		if(strcmp(iterator1.current->charString, iterator2.current->charString))
		{
			return false;
		}

		//-- checks the equality of the character strings of the next elements,
		//-- if both are not equal NULL
		if( (iterator1.current->next && iterator1.current->next) &&
			strcmp(iterator1.current->next->charString, iterator2.current->next->charString))
		{
			return false;
		}

		//-- checks the equality of the character strings of the previous elements,
		//-- if both are not equal NULL
		if( (iterator1.current->previous && iterator1.current->previous) &&
			strcmp(iterator1.current->previous->charString, iterator2.current->previous->charString))
		{
			return false;
		}
	}

	//-- if operator==() reaches this position, the both iterators must be equal
	return true;
}
